package com.monkey.web.context.strategy;

import com.monkey.core.plugin.domain.Treeable;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * Project  : monkey
 * Author   : Wu Tian Qiang
 * Date     : 2016/9/1
 */
public abstract class AbstractCtrlReturnValueHandler implements CtrlReturnValueHandler {

    public boolean isTreeable(Object returnValue) {
        return returnValue instanceof Treeable;
    }


    //http://xxx.com/user/info?fields=id,name,age,teacher[id:name:age]
    protected Object exportResultData(Object returnValue, String fieldStr) {
        if (StringUtils.isEmpty(fieldStr)) {
            return returnValue;
        }
        try {
            Map<String, Object> data = new HashMap<>();
            handleFirstLay(returnValue, fieldStr, data);
            return data;
        } catch (InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 处理第一层的数据，id,name,age,
     *
     * @param returnValue
     * @param fieldStr
     * @param data
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private void handleFirstLay(Object returnValue, String fieldStr, Map<String, Object> data) throws IllegalAccessException, InvocationTargetException {
        String[] fields = resolveFirstLayFields(fieldStr);
        for (String field : fields) {
            if (isHaveSecondLay(field)) {
                handleSecondLay(returnValue, data, field);
            } else {
                Object value = getPropertyValue(returnValue, field);
                data.put(field, value);
            }
        }
        if (isTreeable(returnValue)) {
            Treeable tree = (Treeable) returnValue;
            List children = tree.getChildren();
            List<Object> childrenList = new ArrayList<>();
            for (Object child : children) {
                Map<String, Object> childMap = new HashMap<>();
                handleFirstLay(child, fieldStr, childMap);
                childrenList.add(childMap);
            }
            data.put("children", childrenList);
        }
    }

    /**
     * 处理第二层的数据  teacher[id:name:age]
     *
     * @param returnValue
     * @param data
     * @param field
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private void handleSecondLay(Object returnValue, Map<String, Object> data, String field) throws IllegalAccessException, InvocationTargetException {
        String property = field.substring(0, field.lastIndexOf('['));
        String[] secondFields = resolveSecondLayFields(field);
        Object secondValue = getPropertyValue(returnValue, property);
        if (secondValue instanceof Collection) {
            List<Object> list = new ArrayList<>();
            for (Object o : (Collection) secondValue) {
                Map<String, Object> secondMap = new HashMap<>();
                for (String secondField : secondFields) {
                    secondMap.put(secondField, getPropertyValue(o, secondField));
                }
                list.add(secondMap);
            }
            data.put(property, list);
        } else {
            Map<String, Object> secondMap = new HashMap<>();
            for (String secondField : secondFields) {
                secondMap.put(secondField, getPropertyValue(secondValue, secondField));
            }
            data.put(property, secondMap);
        }
    }

    /**
     * 通过一个对象获取指定属性的值
     *
     * @param instance
     * @param field
     * @return
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private Object getPropertyValue(Object instance, String field) throws IllegalAccessException, InvocationTargetException {
        Class clzz = instance.getClass();
        PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(clzz, field);
        Assert.notNull(propertyDescriptor, "Controller返回的对象中没有fields传入的属性：" + field);
        return propertyDescriptor.getReadMethod().invoke(instance);
    }

    /**
     * 把二级属性解析成一个字符数组
     *
     * @param field
     * @return
     */
    private String[] resolveSecondLayFields(String field) {
        int beginIndex = field.indexOf('[') + 1;
        int endIndex = field.lastIndexOf(']');
        String[] fileds = field.substring(beginIndex, endIndex).split(":");
        if (fileds.length == 0) {
            throw new IllegalArgumentException("fields的二级请求参数格式错误，属性之间以冒号分隔，请传入正确的格式");
        }
        return fileds;
    }

    /**
     * 判断是否存在二级属性
     *
     * @param field
     * @return
     */
    private boolean isHaveSecondLay(String field) {
        return field.contains("[") && field.contains("]");
    }

    /**
     * 把一级级属性解析成一个字符数组
     *
     * @param fieldStr
     * @return
     */
    private String[] resolveFirstLayFields(String fieldStr) {
        String[] fileds = fieldStr.split(",");
        if (fileds.length == 0) {
            throw new IllegalArgumentException("fields请求参数格式错误，属性之间以逗号分隔，请传入正确的格式");
        }
        return fileds;
    }

    protected List<Object> exportResultList(String fieldStr, List list) {
        List<Object> dataList = new ArrayList<>();
        for (Object o : list) {
            Object data = exportResultData(o, fieldStr);
            dataList.add(data);
        }
        return dataList;
    }


    protected Map<String, Object> exportResultPage(String fieldStr, Page page) {
        Map<String, Object> data = new HashMap<>();
        data.put("page", page.getNumber());
        data.put("size", page.getSize());
        data.put("totalAmount", page.getTotalElements());
        data.put("totalPages", page.getTotalPages());
        data.put("elements", exportResultList(fieldStr, page.getContent()));
        return data;
    }

}
